package com.shanzmoo.core.manager.store;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.shanzmoo.base.bean.PageRespBase;
import com.shanzmoo.base.constant.e.SysBillTypeEnum;
import com.shanzmoo.core.cache.CurrentUserCache;
import com.shanzmoo.core.manager.CodeManager;
import com.shanzmoo.db.product.entity.ProductSkuEntity;
import com.shanzmoo.db.product.service.IProductSkuService;
import com.shanzmoo.db.store.entity.*;
import com.shanzmoo.db.store.entity.query.StoreStockQuery;
import com.shanzmoo.db.store.entity.vo.StoreStockVO;
import com.shanzmoo.db.store.service.IStoreInfoService;
import com.shanzmoo.db.store.service.IStoreStockCheckBillDetailService;
import com.shanzmoo.db.store.service.IStoreStockCheckBillService;
import com.shanzmoo.db.store.service.IStoreStockService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 库存实时明细 管理器
 *
 * @author fs 2021-03-09
 */
@Slf4j
@Component
public class StoreStockManager {

    @Autowired
    private IStoreStockService storeStockService;
    @Autowired
    private IStoreStockCheckBillService storeStockCheckBillService;
    @Autowired
    private IStoreStockCheckBillDetailService storeStockCheckBillDetailService;
    @Autowired
    private IStoreInfoService storeInfoService;
    @Autowired
    private IProductSkuService productSkuService;
    @Autowired
    private CodeManager codeManager;

    /**
     * 分页查询
     */
    public PageRespBase<StoreStockVO> queryPage(StoreStockQuery query) {
        Page page = PageHelper.startPage(query.getPageNum(), query.getPageSize());
        List<StoreStockVO> reList = storeStockService.queryPageList(query);

        PageRespBase<StoreStockVO> result = PageRespBase.create(page, reList);
        PageHelper.clearPage();
        return result;
    }

    public void setAlarm(StoreStockEntity entity) {
        storeStockService.update(Wrappers.<StoreStockEntity>lambdaUpdate()
                .eq(StoreStockEntity::getId,entity.getId())
                .set(StoreStockEntity::getAlarmNum,entity.getAlarmNum())
        );
    }

    /**
     * sku和仓库编码校验
     * @param tmpSkus
     * @param storeCodes
     */
    public void skuStockCheck(List<String> tmpSkus,List<String> storeCodes){
        Set<String> skus = new HashSet<>();
        for(String sku:tmpSkus){
            if(skus.contains(sku)){
                Assert.isTrue(false,"sku重复");
            }else{
                ProductSkuEntity db = productSkuService.lambdaQuery().eq(ProductSkuEntity::getSku,sku).one();
                Assert.notNull(db,StrUtil.format("sku[{}]不存在",sku));
                skus.add(sku);
            }
        }
        Map<String,Boolean> storeCodeMap = new HashMap<>();
        for(String storeCode:storeCodes){
            Assert.notBlank(storeCode,"仓库编号不可为空");
            if(storeCodeMap.get(storeCode) == null){
                StoreInfoEntity db = storeInfoService.lambdaQuery().eq(StoreInfoEntity::getCode,storeCode).one();
                Assert.notNull(db,StrUtil.format("仓库[{}]不存在",storeCode));
                storeCodeMap.put(storeCode,true);
            }
        }
    }

    public void createCheckStock(List<StoreStockCheckBillDetailEntity> list) {
        Assert.notEmpty(list,"当前数据为空");
        skuStockCheck(CollUtil.getFieldValues(list,"sku",String.class),CollUtil.getFieldValues(list,"storeCode",String.class));
        StoreStockCheckBillEntity check = new StoreStockCheckBillEntity();
        check.setBillNo(codeManager.generateBillNo(SysBillTypeEnum.CHECK_BILL));
        check.setStatus(0);
        check.setCreateUser(CurrentUserCache.getUserId());
        check.setCreateTime(LocalDateTime.now());
        boolean flag = storeStockCheckBillService.save(check);
        Assert.isTrue(flag,"盘点单创建失败");
        for (StoreStockCheckBillDetailEntity one:list){
            one.setBillId(check.getId());
            one.setCreateTime(LocalDateTime.now());
        }
        flag = storeStockCheckBillDetailService.saveBatch(list);
        Assert.isTrue(flag,"盘点明细创建失败");
    }

    /**
     * 根据流水更新实时库存
     * 注意：事务传播行为：如果已经存在一个事务，支持当前事务。如果没有一个活动的事务，则抛出异常。要求，调用该方法的地方必须开启事务
     * @author Gzhao 2021/3/13
     * @param stockIoList 库存流水信息
     * @param currentUserId 当前操作人
     * @return
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.MANDATORY)
    public void updateByIoList(List<StoreStockIoEntity> stockIoList, Integer currentUserId) {
        for (StoreStockIoEntity ioEntity : stockIoList) {
            /*
                1. 获取实时库存
                2. 若未获取到，新增一条库存记录
                3. 根据版本号更新库存
             */
            String sku = ioEntity.getSku();
            String storeCode = ioEntity.getStoreCode();

            Assert.isTrue(StrUtil.isNotEmpty(sku),"未获取到sku信息，更新库存失败");
            Assert.isTrue(StrUtil.isNotEmpty(storeCode),"未获取到仓库编码信息，更新库存失败");

            StoreStockEntity stockEntity = storeStockService.getBySkuAndStoreCode(sku, storeCode);
            if (ObjectUtil.isNull(stockEntity)) {
                stockEntity = StoreStockEntity.createInitVersion(sku, storeCode, currentUserId);
                storeStockService.save(stockEntity);
            }
            storeStockService.updateStockByIo(ioEntity, stockEntity.getVersionId());
        }
    }

    /**
     * 根据流水更新实时库存
     *
     * @author Gzhao 2021/3/14
     * @param
     * @return
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.MANDATORY)
    public void updateByIo(StoreStockIoEntity ioEntity, Integer currentUserId) {
        List<StoreStockIoEntity> stockIoList = new ArrayList<>();
        stockIoList.add(ioEntity);

        updateByIoList(stockIoList, currentUserId);
    }
}
